package com.sfac.hqyj.springBoot.modules.test.service.impl;


import com.sfac.hqyj.springBoot.modules.common.entity.ResultEntity;
import com.sfac.hqyj.springBoot.modules.common.entity.SearchBean;
import com.sfac.hqyj.springBoot.modules.test.entity.Student;
import com.sfac.hqyj.springBoot.modules.test.repository.StudentRepository;
import com.sfac.hqyj.springBoot.modules.test.service.StudentService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;


@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Override
    @Transactional
    public ResultEntity<Student> insertStudent(Student student) {
        studentRepository.saveAndFlush(student);
        return new ResultEntity<Student>(ResultEntity.ResultStatus.SUCCESS.code,
                "Insert success.", student);
    }

    @Override
    @Transactional
    public ResultEntity<Student> updateStudent(Student student) {
//        studentRepository.saveAndFlush(student);
        studentRepository.updateStudent(student);
        return new ResultEntity<Student>(ResultEntity.ResultStatus.SUCCESS.code,
                "Update success.", student);
    }

    @Override
    @Transactional
    public ResultEntity<Object> deleteStudent(int id) {
        studentRepository.deleteById(id);
        return new ResultEntity<Object>(ResultEntity.ResultStatus.SUCCESS.code,
                "Delete success.");
    }

    @Override
    public Student getStudentById(int id) {
//        return studentRepository.findById(id).orElse(null);
        return studentRepository.getStudentById(id);
    }

    @Override
    public Page<Student> getStudentsBySearchBean(SearchBean searchBean) {
        searchBean.initSearchBean();
//        return exampleAndPage(searchBean);
        return criteriaAndPage(searchBean);
    }

    public Page<Student> exampleAndPage(SearchBean searchBean) {
        Sort.Direction direction = StringUtils.isBlank(searchBean.getDirection()) ||
                searchBean.getDirection().equalsIgnoreCase("asc") ?
                Sort.Direction.ASC : Sort.Direction.DESC;
        String orderBy = StringUtils.isBlank(searchBean.getOrderBy()) ?
                "id" : searchBean.getOrderBy();
        Sort sort = Sort.by(direction, orderBy);
        PageRequest pageRequest = PageRequest.of(searchBean.getCurrentPage() - 1,
                searchBean.getPageSize(), sort);

        Student student = new Student();
        student.setStudentName(searchBean.getKeyWord());
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withMatcher("studentName", matcher -> matcher.contains());
        Example<Student> example = Example.of(student, exampleMatcher);

        return studentRepository.findAll(example, pageRequest);
    }

    public Page<Student> criteriaAndPage(SearchBean searchBean) {
        Sort.Direction direction = StringUtils.isBlank(searchBean.getDirection()) ||
                searchBean.getDirection().equalsIgnoreCase("asc") ?
                Sort.Direction.ASC : Sort.Direction.DESC;
        String orderBy = StringUtils.isBlank(searchBean.getOrderBy()) ?
                "id" : searchBean.getOrderBy();
        Sort sort = Sort.by(direction, orderBy);
        PageRequest pageRequest = PageRequest.of(searchBean.getCurrentPage() - 1,
                searchBean.getPageSize(), sort);

        /**
         * -构造语句 select * from test_student where createDate>=? and
         * (studentName like ? or id between 10 and 20) order by id desc limit ?
         */
        Specification<Student> specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery,
                                         CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.and(
                        criteriaBuilder.greaterThanOrEqualTo(
                                root.get("createDate").as(LocalDateTime.class),
                                LocalDateTime.of(2021, 1, 20, 0, 0)),
                        criteriaBuilder.or(
                                criteriaBuilder.like(root.get("studentName").as(String.class),
                                        String.format("%%%s%%", searchBean.getKeyWord())),
                                criteriaBuilder.between(root.get("id"), 10, 20)
                        )
                );
            }
        };

        return studentRepository.findAll(specification, pageRequest);
    }

    @Override
    public Student findByStudentName(String studentName) {
        return studentRepository.findByStudentName(studentName);
    }
}
